Помогни ни да направим Uroci.net по - богат! Добави урок

C++ част.7 (Член функции на клас)

C++ » C++
fix3d   трудност:    видян: 43598



Двусмислие
Двусмислие може да възникне във връзка с неявното извикване на оператори конвертори. Например,

extern void f( int );
extern void f( SmallInt );
Token tok( "string constant", 3 );
f( tok ); // error: ambiguous

Token дефинира оператор конвертор както за SmallInt така и за int: двете преобразувания са еднакво възможни. Обръщението f(tok) е двусмислено, понеже компилаторът не може да избере измежду двата конвертора. Затова обръщението предизвиква грешка по време на компилация. Програмистът може да разреши двусмислието като направи преобразуването явно:

// explicit convertion resolve ambiguityf( int(tok) );

Ако Token::Operator int() не е дефиниран, обръщението няма да бъде двусмислено. Ще бъде изпълнен Token::Operator SmallInt(). Фактът, че SmallInt дефинира оператор конвертор int не се разглежда. При определяне на възможните преобразувания на един обект, се преглежда само първото ниво на операторите конвертори, дефинирани от потребителя.

Ако е възможно прилагането на два оператора за преобразуване, но при единия има точно съответствие, а другият изисква стандартно преобразуване, няма двусмислие - избира се оператора конвертор с точното съответствие. Например,

class Token{public:
operator float();
operator int();
...};

Обаче, ако и двата оператора конвертора са еднакво приложими, те се отбелязват като двусмислени:

// error: both operators float() and int()long lval = tok;

Двусмислие може да възникне и когато два класа дефинират преобразувание помежду си. Например,

SmallInt::SmallInt( Token& );
Token::Operator SmallInt();
extern void f( SmallInt );
Token tok( "pointer to class member", 197 );// error: two possible user-defined conversionsf( tok );

В този случай съществуват два еднакво възможни начина за преобразуване на tok в обект на SmallInt. Обръщението е двусмислено понеже няма начин компилаторът да направи избор между двата начина; обръщението се отбелязва като грешка по време на компилация. Програмистът може да разреши двусмислието като направи преобразуването явно. Например,

// explicit convertion resolves ambiguity
// Token::Operator SmallInt() invoked
f( (SmallInt)tok );

Програмистът може да разреши двусмислието и чрез явно извикване на оператора конвертор на класа Token:

// explicit conversion resolves ambiguity
f( tok.operator SmallInt() ):

Забележете, че явното преобразуване в записа на функцията все още е двусмислено.

// error: still ambiguous
f( SmallInt(tok) );
SmallInt(Token&) и Token::Operator SmallInt() са еднакво възможни интерпретации на обръщението.

Една втора форма на двусмисилие се свързва с читателя на програма, която използува оператори конвертори. Когато един обект на SmallInt се преобразува до стойност от тип int, значението на това преобразувание е ясно. Когато един обект на String се преобразува до типа char*, значението на това преобразувание също е ясно. И в двата случая съществува съответствие едно-към-едно между вградените типове данни и вътрешното представяне на типа на класа. Когато, обаче няма логическо съответствие между оператора конвертор и типа на класа, използуването на обектите на класа може да стане двусмислено за читателя на програмата. Например,

class Date {
public:
// guess which member is returned!
operator int();
private:
Int month, day, year;};

Каква стойност трябва да бъде върната от оператора конвертор int на Date? Какъвто и избор да бъде направен по каквато и да било добра причина, използуването на обекти на Date ще бъде двусмислено за читателя на програмата понеже няма логично съответствие едно-към-едно. В този случай би било много по-добре да не се дефинира оператор за конвертиране.

Упражнение 7-28. Какви оператори конвертори са необходими за поддържане на следното използуване на обекти на класа String?

extern int strlen( const char* );
const maxLen = 32;
String st = "a string";
int len = strlen( st );
if ( st >= maxLen ) ... String st2 = maxLen;

Упражнение 7-29. Разгледайте предимствата и недостатъците от поддържането оператора конвертор, представен чрез

if ( st >= maxLen ) ...

Упражнение 7-30. Един интересен оператор конвертор за BinTree връща обект на класа IntArray от стойности на INode (Раздел 2.8 съдържа дефиницията на класа IntArray). Реализирайте следните два оператора конвертора:

BinTree::BinTree( IntArray& );
BinTree::Operator IntArray();

Забележете, че реда за преглед на дървото трябва да бъде еднакъв и за двата оператора. Може да бъде установен един предварително установен ред за преглед със следната обща форма:

BinTree::preorder( /* ??? */ ) {
if ( !node ) return;
node->visit( /* ??? *? ); // do work
if ( left ) left->preOrder( /* ??? */ );
if ( right ) right->preOrder( /* ??? */ );

Упражнение 7-31. Предишното упражнение предлага обработване на изрази, включващи обекти от двата класа IntArray и BinTree. Например,

extern BinTree bt;
extern IntArray ia;

if ( ia == bt ) ...

Редът на операциите е следният: Извиква се оператора конвертор на BinTree за да преобразува bt в обект на класа IntArray. Тогава се извиква оператора за равенство на IntArray за да сравни двата обекта на класа IntArray. Какво ще се случи, обаче, ако класа IntArray дефинира следните два оператора конвертори?

IntArray::IntArray( BinTree& );
IntArray::Operator BinTree();


Страници: «8 9 10 11

Сподели урока:



Регистрирайте се, за да добавите коментар


Калдейта Ком ЕООД - © 2003-. Всички права запазени.
Препоръчваме: IT Новини